package code.example.base.util.concurrent.lock.seqence;


import code.example.tool.LogFactory;
import code.example.tool.SleepUtils;

/**
 *  synchronized 线程获得锁的顺序
 *  由队列保存等待的线程 ：
 *
 *
 */
public class SyncRunSequence  {
    public   void doSomething(){
        LogFactory.getLog().info(Thread.currentThread().getName()+" to getLock.......");
        synchronized (this){
            LogFactory.getLog().info(Thread.currentThread().getName()+" got lock");
            SleepUtils.sleepSecond(15);
            LogFactory.getLog().info(Thread.currentThread().getName()+" release lock");
        }

    }

    public   void fromWait(){
        LogFactory.getLog().info(Thread.currentThread().getName()+" to getLock.......");
        synchronized (this){
            LogFactory.getLog().info(Thread.currentThread().getName()+" got lock to waiting .......");
            try {
                this.wait();
            }catch (InterruptedException ie){};
            LogFactory.getLog().info(Thread.currentThread().getName()+" waiting finish,release lock");
        }

        /*this.notify();*/
    }
    public synchronized  void notifyAllWait(){
        LogFactory.getLog().info("notify all  thread --blocked");
        this.notifyAll();
        LogFactory.getLog().info("notify all wait thread");
    }
    public synchronized  void notifyOneWait(){
        LogFactory.getLog().info("notify one  wait thread ---blocked");
        this.notify();
        LogFactory.getLog().info("notify one wait thread");
    }

    static class DoRunnable implements Runnable{
        SyncRunSequence syncRunSequence =null;
        DoRunnable(SyncRunSequence syncRunSequence){
            this.syncRunSequence = syncRunSequence;
        }
        @Override
        public void run () {
            syncRunSequence.doSomething();
        }
    }

    static class WaitRunnable implements Runnable{
        SyncRunSequence syncRunSequence =null;
        WaitRunnable(SyncRunSequence syncRunSequence){
            this.syncRunSequence = syncRunSequence;
        }
        @Override
        public void run () {
            syncRunSequence.fromWait();
        }
    }

    public static void main(String args []){
        SyncRunSequence syncRunSequence = new SyncRunSequence();
        DoRunnable doRunnable = new DoRunnable(syncRunSequence);
        Thread thread0 = new Thread(doRunnable,"Thread-0");
        Thread thread1 = new Thread(doRunnable,"Thread-1");
        Thread thread2 = new Thread(doRunnable,"Thread-2");
        Thread thread3 = new Thread(doRunnable,"Thread-3");
        Thread thread4 = new Thread(doRunnable,"Thread-4");
        Thread thread5 = new Thread(doRunnable,"Thread-5");
        thread0.start();
        SleepUtils.sleepSecond(1);
        thread1.start();
        SleepUtils.sleepSecond(1);
        thread2.start();
        SleepUtils.sleepSecond(1);
        thread3.start();
        SleepUtils.sleepSecond(1);
        thread4.start();
        SleepUtils.sleepSecond(1);
        thread5.start();
        SleepUtils.sleepSecond(1);

        WaitRunnable waitRunnable = new WaitRunnable(syncRunSequence);
        Thread threadWait0 = new Thread(waitRunnable,"Thread-wait-0");
        Thread threadWait1 = new Thread(waitRunnable,"Thread-wait-1");
        Thread threadWait2 = new Thread(waitRunnable,"Thread-wait-2");
        Thread threadWait3 = new Thread(waitRunnable,"Thread-wait-3");
        Thread threadWait4 = new Thread(waitRunnable,"Thread-wait-4");
        Thread threadWait5 = new Thread(waitRunnable,"Thread-wait-5");
        threadWait5.start();
        SleepUtils.sleepSecond(1);
        threadWait4.start();
        SleepUtils.sleepSecond(1);
        threadWait3.start();
        SleepUtils.sleepSecond(1);
        threadWait2.start();
        SleepUtils.sleepSecond(1);
        threadWait1.start();
        SleepUtils.sleepSecond(1);
        threadWait0.start();
        SleepUtils.sleepSecond(1);
        Thread threadNew = new Thread(doRunnable,"Thread-New");
        threadNew.start();
        try {
            thread5.join();
        }catch (Exception e){};
        syncRunSequence.notifyOneWait();
        // syncRunSequence.notifyOneWait();
    }
}
